﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace TheOliver.Controls
{
    public class ImageSpindle : Panel
    {
        Point _mousePoint;
        double _height;
        double _width;
        bool _isMouseOver;

        public ImageSpindle()
        {
            this.Loaded += (s, e) =>
                {
                    if (DesignerProperties.GetIsInDesignMode(this))
                    {
                        return;
                    }

                    this.MouseMove += (s1, e1) =>
                        {
                            _mousePoint = e1.GetPosition(this);
                        }; 

                    CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
                };

            this.MouseEnter += (s, e) =>
                {
                    _isMouseOver = true;
                };

            this.MouseLeave += (s, e) =>
                {
                    _isMouseOver = false;
                };
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            _height = availableSize.Height;
            _width = availableSize.Width;

            var images = this.Children.OfType<Image>();
            int imageCount = images.Count();
            if (imageCount > 0)
            {
                double step = 360.0 / imageCount;
                double currentStep = 0;
                foreach (var image in images)
                {
                    UpdateImage(image, currentStep);
                    currentStep += step;
                }
            }
            return base.MeasureOverride(availableSize);
        }

        private Image UpdateImage(Image image, double step)
        {
            image.Height = ImageHeight;
            image.Width = ImageWidth;
            image.Margin = new Thickness(
                (_width - ImageWidth) / 2, (_height - ImageHeight) / 2, 
                (_width - ImageWidth) / 2, (_height - ImageHeight) / 2); 
            image.RenderTransformOrigin = new Point(0.5, 0.5);
            image.Stretch = ImageStretch;

            PlaneProjection pp = new PlaneProjection();
            pp.CenterOfRotationZ = SpindleCenterOfRotation;
            pp.RotationY = step;
            image.Projection = pp;

            return image;
        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            if (StopWhenMouseLeft)
            {
                if (!_isMouseOver)
                {
                    return;
                }
            }

            if (double.IsNaN(_width) || _width == 0)
            {
                return;
            }

            foreach (var image in this.Children.OfType<Image>())
            {
                PlaneProjection pp = image.Projection as PlaneProjection;
                if (pp != null)
                {
                    pp.RotationY += ((_mousePoint.X - (_width / 2)) / _width) * 10;
                }
                image.Opacity = (_mousePoint.Y / _height) * 0.5 + 0.5;
            }
        }

        #region Properties

        public Stretch ImageStretch
        {
            get { return (Stretch)GetValue(ImageStretchProperty); }
            set { SetValue(ImageStretchProperty, value); }
        }

        public static readonly DependencyProperty ImageStretchProperty =
            DependencyProperty.Register(
                "ImageStretch", 
                typeof(Stretch), 
                typeof(ImageSpindle), 
                new PropertyMetadata(Stretch.Uniform, OnValueChanged));

        public double ImageWidth
        {
            get { return (double)GetValue(ImageWidthProperty); }
            set { SetValue(ImageWidthProperty, value); }
        }

        public static readonly DependencyProperty ImageWidthProperty =
            DependencyProperty.Register(
                "ImageWidth", 
                typeof(double), 
                typeof(ImageSpindle), 
                new PropertyMetadata(160.0, OnValueChanged));

        public double ImageHeight
        {
            get { return (double)GetValue(ImageHeightProperty); }
            set { SetValue(ImageHeightProperty, value); }
        }

        public static readonly DependencyProperty ImageHeightProperty =
            DependencyProperty.Register(
                "ImageHeight", 
                typeof(double), 
                typeof(ImageSpindle), 
                new PropertyMetadata(120.0, OnValueChanged));

        public double SpindleCenterOfRotation
        {
            get { return (double)GetValue(SpindleCenterOfRotationProperty); }
            set { SetValue(SpindleCenterOfRotationProperty, value); }
        }

        public static readonly DependencyProperty SpindleCenterOfRotationProperty =
            DependencyProperty.Register(
                "SpindleCenterOfRotation", 
                typeof(double), 
                typeof(ImageSpindle), 
                new PropertyMetadata(-160.0, OnValueChanged));

        private static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ImageSpindle spindle = sender as ImageSpindle;
            spindle.InvalidateMeasure();
        }

        public bool StopWhenMouseLeft
        {
            get { return (bool)GetValue(StopWhenMouseLeftProperty); }
            set { SetValue(StopWhenMouseLeftProperty, value); }
        }

        public static readonly DependencyProperty StopWhenMouseLeftProperty =
            DependencyProperty.Register(
                "StopWhenMouseLeft", 
                typeof(bool), 
                typeof(ImageSpindle), 
                new PropertyMetadata(true));

        #endregion

    }
}
